﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;

using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Threading;
using ScrumTable.Common.Data;
using ScrumTable.Config.ConfigManagement;
using ScrumTable.BL.DM.DataManagement;
using ScrumTable.Common;
using ScrumTable.UI.ViewModel.Data;
using ScrumTable.UI.ViewModel.Dynamic;
using ScrumTable.UI.ViewModel.Extension;

#endregion

namespace ScrumTable.UI.ViewModel
{
    public abstract class ViewModelItemBase<T> : ViewModelBase, IScrumItemViewModel<T>
        where T : ScrumItemBase, IScrumItem
    {
        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------

        private bool _isPlacedOnScrumPoker;
        private object _customFields;
        private T _original;
        private string _id;
        private ObservableDomainCollection<AttachmentViewModel, Attachment> _attachmentstsAsViewModel;
        private ObservableDomainCollection<AttachmentViewModel, Attachment> _attachmentsAsViewModelWithPlaceholder;
        private int _selectedAttachment = 0;
        

        #endregion


        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------

        public bool IsDisposed
        {
            get
            {
                if(((IDisposableObject) _original).IsDisposed)
                {
                    var orginal = ScrumDataGlobal.FindScrumItem<T>(_id) as T;
                    if( orginal != null)
                    {
                        SetOrginal(orginal, false);
                    }
                }
                
                return ((IDisposableObject) _original).IsDisposed;
            }
        }

        

        public bool IsDisposing
        {
            get { return ((IDisposableObject)_original).IsDisposing; }
        }

     
        public ConfigManager ConfigManager
        {
            get { return ((IAppScreen)Application.Current.MainWindow).ConfigManager; }
        }

        public Predicate<object> CanChangeStateTo
        {
            get { return (o => Original.CanChangeState(Original.ItemType.StateMappings[o.ToString()])); }
        }
 
        public bool IsDescriptionHtml
        {
            get
            {
                if (IsDisposed)
                {
                    return false;
                }
                var meta = Original.ItemType.FieldMeta.TryGetByName("Description");
                return meta != null && Original.ItemType.FieldMeta.TryGetByName("Description").FieldTypeFormat == DataType.Html;
                
            }
        }
        public object CustomFields
        {
            get
            {
                if (_customFields == null)
                {
                    _customFields = DynamicValueResolverLoader.TryGetDynamicValueResolver().GetOtherAttributs(Original);
                }
                return _customFields;
            }
        }


        /// <summary>
        /// Contains Errors occurred on this element
        /// </summary>
        public IList<DomainSyncErrorInfo> SynchronizationErrors
        {
            get { return IsDisposed ? null : Original.SynchronizationErrors; }
        }

        /// <summary>
        /// Contains if a error is active
        /// </summary>
        public bool HasSynchronizationErrors
        {
            get { return IsDisposed ? false : Original.HasSynchronizationErrors; }
        }
     
        /// <summary>
        /// Gets the original bug from the BL.
        /// </summary>
        /// <value></value>
        public T Original
        {
            get { return IsDisposed ? null : _original; }
            private set { _original = value; }
        }


        public object this[string name]
        {
            get
            {

                return IsDisposed ? null :Original[name];
            }
            set
            {
                Original[name] = value;
            }
        }


        /// <summary>
        /// Gets the name of the bug.
        /// </summary>
        public string Name
        {
            get { return IsDisposed ? null : Original.Name; }
            set
            {
                if (value.Length == 0)
                {
                    throw new Exception();
                }
                Original.Name = value;
                SendPropertyChanged("Name");
                Save();
            }
        }

        public string BackEndId { get { return IsDisposed ? null : Original.BackEndId; } }

        /// <summary>
        /// Gets the parent of the bug
        /// </summary>
        public DomainBase Parent
        {
            get
            {
                return IsDisposed ? null : Original.Parent;
            }
        }

        /// <summary>
        /// Specifies the state for the current ScrumItem.
        /// </summary>
        public ScrumState State
        {
            get { return IsDisposed ? null : Original.State; }
            set
            {
                if (value != State)
                {
                    if (Original.ItemType.CanChangeState(Original.State, value))
                    {
                        Original.State = value;
                        Save();
                    }
                }
                SendPropertyChanged("State");
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this bug is placed on the scrumpoker. 
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is placed on the scrumpoker; otherwise, <c>false</c>.
        /// </value>
        public bool IsPlacedOnScrumPoker
        {
            get { return _isPlacedOnScrumPoker; }
            set
            {
                _isPlacedOnScrumPoker = value;
                SendPropertyChanged("IsPlacedOnScrumPoker");
            }
        }

        /// <summary>
        /// Gets the bug description text.
        /// </summary>
        public string Description
        {
            get { return IsDisposed ? null : Original.Description; }
            set
            {
                Original.Description = value;
                SendPropertyChanged("Description");
                Save();
            }
        }

        /// <summary>
        /// Sorting property
        /// </summary>
        public abstract double? Sorting { get; }

        /// <summary>
        /// Gets the id of the bug.
        /// </summary>
        public string Id
        {
            get { return IsDisposed ? null : Original.Id; }
        }

        /// <summary>
        /// Gets the attachments for this user story.
        /// </summary>
        /// <value>attachments of this story.</value>
        public ObservableDomainCollection<AttachmentViewModel, Attachment> AttachmentsAsViewModel
        {
            get
            {
                if (_attachmentstsAsViewModel == null)
                {
                    _attachmentstsAsViewModel = new ObservableDomainCollection<AttachmentViewModel, Attachment>();
                    _attachmentstsAsViewModel.Fill(Original.Attachments, attachment => new AttachmentViewModel(attachment));
                }
                return _attachmentstsAsViewModel;
            }
        }



        /// <summary>
        /// Gets the attachments for this user story.
        /// </summary>
        /// <value>attachments of this story.</value>
        public ObservableDomainCollection<AttachmentViewModel, Attachment> AttachmentsAsViewModelWithPlaceholder
        {
            get
            {
                if (_attachmentsAsViewModelWithPlaceholder == null)
                {
                    _attachmentsAsViewModelWithPlaceholder = new ObservableDomainCollection<AttachmentViewModel, Attachment>();
                    _attachmentsAsViewModelWithPlaceholder.Fill(Original.Attachments, attachment => new AttachmentViewModel(attachment));
                }
                
                var itemsView = (IEditableCollectionView)CollectionViewSource.GetDefaultView(_attachmentsAsViewModelWithPlaceholder);
                //gets lost sometimes; add it again :)
                if (itemsView.NewItemPlaceholderPosition == NewItemPlaceholderPosition.None)
                {
                    itemsView.NewItemPlaceholderPosition = NewItemPlaceholderPosition.AtEnd;
                }
                return _attachmentsAsViewModelWithPlaceholder;
            }
        }

      

        /// <summary>
        /// Command for adding a new attachment
        /// </summary>
        /// <value>Command for adding a new attachment</value>
        public ICommand AddAttachment
        {
            get
            {
                return new RelayCommand(
                    param =>
                        {
                            var attachment = Attachments.AddNew();
                            attachment.Name = "new.jpg";
                            SelectedAttachment = Attachments.Count - 1;
                        }, param => true);
            }
        }


        
        public int SelectedAttachment
        {
            get { return (Attachments.Count == 0) ? -1 : _selectedAttachment; }
            set
            {
                _selectedAttachment = value;
                SendPropertyChanged("SelectedAttachment");
            }
        }

        public DomainCollection<Attachment> Attachments
        {
            get { return IsDisposed ? null : Original.Attachments; }
        }

        /// <summary>
        /// Specifies the bug user story ranking.
        /// </summary>
        public double? Ranking
        {
            get { return IsDisposed ? null : Original.Ranking; }
            set
            {
                Original.Ranking = value;
                SendPropertyChanged("Ranking");
                Save();
            }
        }

        /// <summary>
        /// Specifies the assigned project member.
        /// </summary>
        /// <summary>
        /// Specifies the assigned project member.
        /// </summary>
        public MemberViewModel AssignedMember
        {
            get
            {
                if (Original == null || Original.AssignedMember == null) return null;
                return new MemberViewModel(Original.AssignedMember);
            }
            set
            {
                Original.AssignedMember = value == null ? null : value.Original;
                SendPropertyChanged("AssignedMember");
                Save();
            }
        }
       

      
        #endregion
        
        #region Constructors / Destructor
        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------
        /// <summary>
        /// Initializes a new instance of the <see cref="BugViewModel"/> class.
        /// </summary>
        /// <param name="orginal">The bug.</param>
        public ViewModelItemBase(T orginal)
        {
            PreCondition.AssertNotNull(orginal, "orginal");
            SetOrginal(orginal, true);
            
        }

     

        #endregion


        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        private void SetOrginal(T orginal, bool isFirstInit)
        {

            if (!isFirstInit && _original !=  null)
            {
                _original.PropertyChanged -= OnOrginalPropertyChanged;
            }

            Original = orginal;
            _id = orginal == null ? null : orginal.Id;

            if (!isFirstInit)
            {
                if (_attachmentstsAsViewModel != null)
                {
                    _attachmentstsAsViewModel.Dispose();
                    _attachmentstsAsViewModel = null;
                    //fire that all properties has changed!
                    SendPropertyChanged(null);
                }
                if (_attachmentsAsViewModelWithPlaceholder != null)
                {
                    _attachmentsAsViewModelWithPlaceholder.Dispose();
                    _attachmentsAsViewModelWithPlaceholder = null;
                    //fire that all properties has changed!
                    SendPropertyChanged(null);
                }
            }
            if (_original != null)
            {
                Original.PropertyChanged += OnOrginalPropertyChanged;
            }
        }

        protected static CanDropResult CanChangeStateResult<TU>(object obj, ScrumState state)
            where TU : ViewModelItemBase<T>
        {
            CanDropResult result = CanDropResult.None;
            if (obj is TU)
            {
                TU viewModel = (TU)obj;
                if (viewModel.Original != null)
                {
                    if (viewModel.Original.CanChangeState(state))
                    {
                        result = CanDropResult.CanDrop;
                    }
                    else if (!viewModel.Original.StateIsReady)
                    {
                        result = CanDropResult.SaveReason;
                    }
                    else if (viewModel.Original.ContainsChangeState(state))
                    {
                        result = CanDropResult.WorkflowReason;
                    }
                }
            }
            return result;
        }

       
        /// <summary>
        /// Saves this instance.
        /// </summary>
        public void Save()
        {
            if (Original != null)
            {
                Original.Save();
            }
        }

        #endregion



        #region Events
        //--------------------------------------------------------------------
        // Events
        //--------------------------------------------------------------------
     
        protected virtual void OnOrginalPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "IsDisposing" && IsDisposing)
            {
                Dispose();
            }
            SendPropertyChanged(e.PropertyName);
            SendPropertyChanged(Binding.IndexerName);
            //SendPropertyChanged(Binding.IndexerName.Replace("[]", "["+e.PropertyName+"]"));  // TODO would be a lot fast..but does not work 
        }
        #endregion
    }


   
}